package com.shop.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.g3net.tool.CachedClientFactory;
import com.g3net.tool.MailUtil;
import com.g3net.tool.NumberUtils;
import com.g3net.tool.StringUtils;
import com.g3net.tool.cache.CachedClient;

public class CacheUtil {
	private static Logger log = Logger.getLogger(CacheUtil.class);
	public   int SIZE=13;
	private  String[] SERVERS;//服务器列表总数最好保持不变，以免导致现有缓存失效,且不同服务器之间的相对位置也要保持一致
	private  int[] WEIGHTS;
	private  int TOTALW=0;
	//已经无效的cache服务器,这个列表由后台进程定时刷新，如果这个列表不为空，则需要向相关人员发送邮件及时处理
	public final static  Map<String,String> downServers=new HashMap<String, String>();//每次检测前需要将此列表清空
	private  static Map<String,CacheUtil> cus=new HashMap<String, CacheUtil>();//存放所有cache集群访问入口
	public static CacheUtil getInstance(String cacheName,String[] list) throws Exception{
		CacheUtil cu=cus.get(cacheName);//返回集群操作类
		if(cu==null){
			cu=new CacheUtil(cacheName,list);
		}
		return cu;
	}
 	/**
	 * 初始化cache列表
	 * @param list 格式：ip:port,weight
	 * @throws Exception 
	 */
	private CacheUtil(String cacheName,String[] list) throws Exception{
		init(cacheName,list);
	}
	public void init(String cacheName,String[] list)throws Exception{
		if(list==null||list.length==0)
		{
			throw new Exception("CacheUtil 初始化失败==cache服务器列表为空");
		}
		SIZE=list.length;
		boolean isok=false;
		/**
		 * 如果给定的列表服务器总数不对，且只有一台，则使用表示只用主内存服务器
		 */
		if(list.length==1){
			SERVERS=new String[1];
			WEIGHTS=new int[1];
			
			String ip=list[0];
			String[] ss=ip.split(",");
			SERVERS[0]=ss[0];
//			WEIGHTS[0]=ss[1];
			isok=CachedClientFactory.regist(SERVERS[0],
					SERVERS[0],CachedClientFactory.CachedClientType.MemCachedClient);
			log.error("初始化memcache==ip="+SERVERS[0]+" isok="+isok);
			return ;
		}
		if(list.length!=SIZE){
			throw new Exception("CacheUtil 初始化失败==cache服务器列表总数不对 list.size="+list.length+" SIZE="+SIZE);
		}
		SERVERS=new String[SIZE];
		WEIGHTS=new int[SIZE];
		for (int i = 0; i < list.length; i++) {
			String ip=list[i];
			String[] ss=ip.split(",");
			SERVERS[i]=ss[0];
			WEIGHTS[i]=NumberUtils.parseInt(ss[1]);
			TOTALW+=WEIGHTS[i];
			isok=CachedClientFactory.regist(SERVERS[i],
					SERVERS[i],CachedClientFactory.CachedClientType.MemCachedClient);
			log.error("初始化memcache==ip="+SERVERS[i]+" isok="+isok);
		}
		cus.put(cacheName, this);
	}
	/**
	 * 根据给定的key值返回相应的cache服务器操作对象
	 * @param key 
	 * @return
	 */
	public CachedClient getBy(int key,String skey){
		String ip=getIPBy(key,skey);
		if(StringUtils.hasText(ip))return CachedClientFactory.getCachedClient(ip); 
		return null;
	}
	/**
	 * 根据给定的key值返回相应的cache服务器地址
	 * @param key 
	 * @return
	 */
	public String getIPBy(int key,String skey){
		if(SERVERS.length==1){
			return SERVERS[0];
		}
		int tempw=key%TOTALW+1; //使用权重作为分流的准则是为了在服务器列表总数不变的情况下给不同服务器分配不同数量的key
		int currentw=0;
		for (int i = 0; i < WEIGHTS.length; i++) {
			currentw+=WEIGHTS[i];
			if(tempw<=currentw){
				log.debug("选中cache服务器  key="+key+" skey="+skey+" SERVERS["+i+"]="+SERVERS[i]);
				if(downServers.containsKey(SERVERS[i]))
				{
					log.debug("选中cache服务器  "+SERVERS[i]+" 该服务器异常，使用备用机器："+Config.BAK_CACHE_IP);
					return Config.BAK_CACHE_IP;
				}
				return SERVERS[i]; 
			}
		}
		log.error("cache选择出错 没有找到正确的服务器 key="+key);
		return null;
	}
	private static String get(String ip,int port,String cmd,int timeout) throws Exception{
		 InetAddress server=InetAddress.getByName(ip);
		 Socket c=null;
		 StringBuilder sb=new StringBuilder();
		 try{
//			 c=new Socket(server,port);
			 c=new Socket();
			 c.connect(new InetSocketAddress(server, port), timeout);
			 c.setSoTimeout(timeout);
			 BufferedWriter out=new BufferedWriter(new OutputStreamWriter(c.getOutputStream()));
			 out.write(cmd+"\r\n");
			 out.flush();
			 BufferedReader reader=new BufferedReader(new InputStreamReader(c.getInputStream()));
			 String line=null;
			 while (line==null||!line.equalsIgnoreCase("end")) {
				 line=reader.readLine();
				 if(line.contains("items")||line.contains("cmd"))
				 {
					 sb.append("<font color='blue'>"+line+"</font>");		
				 }else if(!line.toLowerCase().startsWith("stat")&&!line.toLowerCase().startsWith("end"))
				 {
					 sb.append("<font color='red'>"+line+"</font>");	
				 }
				 else{
					 sb.append(line);
				 }
				 sb.append(",");
			}
		 }catch (Exception e) {
			// TODO: handle exception
			 //检测到服务器异常时，添加到宕机列表。
			String ipport=ip+":"+port;
			downServers.put(ipport, ipport);
			String host = "mail.3g.net.cn"; // 指定的smtp服务器   
			String from = "yuxiaowei@3g.net.cn"; // 邮件发送人的邮件地址   
			String to = "yuxiaowei@3g.net.cn,zengwenqing@3g.net.cn"; // 邮件接收人的邮件地址   
			final String password = "160376"; //发件人的邮件密码   
			MailUtil.send(host, "来源服务器："+getLocalIP()+" book3.0 memcache 检测邮件", ipport+"==="+e.getLocalizedMessage(), null, null, from, to, password);
			return "<font color='red'>"+e.getLocalizedMessage()+"</font>";
		}finally{
			if(c!=null)
			c.close();
		}
		return sb.toString();
	}
	public Map<String,String> getStatus(){
		if(SERVERS!=null&&SERVERS.length>0)
		{
			Map<String,String> results=new HashMap<String, String>();
			for (int i = 0; i < SERVERS.length; i++) {
				String[] ss=SERVERS[i].split(":");
				try {
					results.put(SERVERS[i]+","+WEIGHTS[i], get(ss[0],Integer.parseInt(ss[1]),"stats",500));
				}  catch (Exception e) {
					// TODO Auto-generated catch block
					results.put(SERVERS[i], e.getLocalizedMessage());
				}
			}
			return results;
		}
		return null;
	}
	/**
	 * 此功能慎用，会清空集群所有缓存
	 * @return
	 */
	public Map<String,String> flushAll(){
		if(SERVERS!=null&&SERVERS.length>0)
		{
			Map<String,String> results=new HashMap<String, String>();
			for (int i = 0; i < SERVERS.length; i++) {
				String[] ss=SERVERS[i].split(":");
				try {
					results.put(SERVERS[i]+","+WEIGHTS[i], get(ss[0],Integer.parseInt(ss[1]),"flush_all",500));
				}  catch (Exception e) {
					// TODO Auto-generated catch block
					results.put(SERVERS[i], e.getLocalizedMessage());
				}
			}
			return results;
		}
		return null;
	}
	public static Map<String,String> getStatus(String[] serverIPs){
		if(serverIPs!=null&&serverIPs.length>0)
		{
			Map<String,String> results=new HashMap<String, String>();
			for (int i = 0; i < serverIPs.length; i++) {
				String[] ss=serverIPs[i].split(":");
				try {
					results.put(serverIPs[i], get(ss[0],Integer.parseInt(ss[1]),"stats",500));
				}  catch (Exception e) {
					// TODO Auto-generated catch block
					results.put(serverIPs[i], e.getLocalizedMessage());
				}
			}
			return results;
		}
		return null;
	}
	/**
	 * 此功能慎用，会清空指定服务器列表所有缓存
	 * @return
	 */
	public static Map<String,String> flushAll(String[] serverIPs){
		if(serverIPs!=null&&serverIPs.length>0)
		{
			Map<String,String> results=new HashMap<String, String>();
			for (int i = 0; i < serverIPs.length; i++) {
				String[] ss=serverIPs[i].split(":");
				try {
					results.put(serverIPs[i], get(ss[0],Integer.parseInt(ss[1]),"flush_all",500));
				}  catch (Exception e) {
					// TODO Auto-generated catch block
					results.put(serverIPs[i], e.getLocalizedMessage());
				}
			}
			return results;
		}
		return null;
	}
	public static String getLocalIP()
	{
		StringBuilder sb=new StringBuilder();
		Enumeration<NetworkInterface> netInterfaces;
		try {
			netInterfaces = NetworkInterface.getNetworkInterfaces();
			
			   while(netInterfaces.hasMoreElements())
			   {
			    NetworkInterface ni=(NetworkInterface)netInterfaces.nextElement();
			    List<InterfaceAddress> ss=ni.getInterfaceAddresses();
			    for(int i=0;i<ss.size();i++){
			    	InetAddress ip = ss.get(i).getAddress();
			    	if( ip.isSiteLocalAddress() 
						    && !ip.isLoopbackAddress() 
						    && ip.getHostAddress().indexOf(":")==-1)
			    	{
			    		sb.append(ip.getHostAddress()+" ");
			    	}
			    			
			    	
			    }
			   }
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			sb.append(e.getLocalizedMessage());
		}
		return sb.toString();
	}
	public static void main(String[] args) {
//		try {
//			String[] list=new String[]{
//			"192.168.1.2:11211,0",
//			"192.168.1.139:11211,3",
//			"192.168.112.52:11211,3",
//			"192.168.1.5:11211,0",
//			"192.168.1.6:11211,0",
//			"192.168.1.7:11211,0",
//			"192.168.1.8:11211,0",
//			"192.168.1.9:11211,0",
//			"192.168.1.10:11211,0",
//			"192.168.1.11:11211,0",
//			"192.168.1.12:11211,0",
//			"192.168.1.13:11211,0",
//			"192.168.1.14:11211,0"};
//			CacheUtil cu=new CacheUtil(list);
////			int c=10000;
////			Map<String,Integer> count=new HashMap<String, Integer>();
////			long start=System.currentTimeMillis();
////			for (int i = 1; i <= c; i++) {
//////				CachedClient s=cu.getBy(i);
////				String s=cu.getIPBy(i,""+i);
////				Integer t=count.get(s.toString());
////				if(t==null)
////				{
////					count.put(s.toString(), 1);
////				}else {
////					t++;
////					count.put(s.toString(), t);
////				}
////			}
////			long end=System.currentTimeMillis();
////			System.out.println("c="+c+" "+(end-start)+"ms");
////			System.out.println(CollectionUtils.toString(count));
////			
////			cu.getBy(4,"4").set("test", "this a test");
////			cu.getBy(4,"4").set("test1", "fsdfa".getBytes());
////			System.out.println((String)cu.getBy(4,"4").get("test"));
////			System.out.println(((byte[])cu.getBy(4,"4").get("test1")).length);
//			
//			
//			;
//			System.out.println(CollectionUtils.toString(cu.getStatus()));
//			CachedClientFactory.clearAll();
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		long start=System.currentTimeMillis();
//		BaseBookDataImp.getExpdate().getTime();
//		long end=System.currentTimeMillis();
//		System.out.println(end-start);
		try {
			System.out.println(getLocalIP());
//			CacheUtil.getInstance(Config.HOT_CACHE_NAME,CommonConfig.readServers(Path.getClassPath("common.xml"),"hcserver"));
			
//			for (int i = 0; i < 1; i++) {
//				String b=(String)CacheUtil.getInstance(null).getBy(13546, "menus_13546").get("menus_13546");
////				byte[] b=(byte[])CacheUtil.getInstance(null).getBy(141703, "con_141703_2").get("con_141703_2");
//				System.out.println(b);
//				StringBuilder bb=(StringBuilder)CacheUtil.getInstance(null).getBy(141703, "con_141703_2").get("con_141703_2");
//				System.out.println(bb.toString().getBytes("utf-8").length);
//			}
//			for (int i = 176000; i > 100000; i--) {
//				int bookid=107094;
//				String key="con_"+bookid+"_1465";//con_172901_40
////				CacheUtil.getInstance(Config.HOT_CACHE_NAME,null).getBy(bookid,key ).set(key, "this is test");
//				String s=(String)CacheUtil.getInstance(Config.HOT_CACHE_NAME,null).getBy(bookid,key ).get(key);
//				System.out.println(s);
//				byte[] ttt=(byte[])CacheUtil.getInstance(Config.HOT_CACHE_NAME,null).getBy(bookid,key ).get(key);
//				System.out.println(new String(ttt,"utf-8"));
//				CacheUtil.getInstance(null).getBy(bookid,key ).delete(key);
//			}
			
//			CacheUtil.getInstance(null).getBy(127624, "info_127624").delete("info_127624");
			
//			byte[] data=(byte[])CacheUtil.getInstance(null).getBy(125335, "img_125335").get("img_125335");
//			System.out.println(data);
//			ExecutorService exe=Executors.newFixedThreadPool(140);
//			for (int i = 0; i < 10000; i++) {
//				exe.execute(new Runnable() {
//					
//					public void run() {
//						// TODO Auto-generated method stub
//						
//						String s="f";
//						int cc=1;
//						long start=System.currentTimeMillis();
////						for (int i = 0; i < cc; i++) {
//////							c.set(String.valueOf(i), s+i);
////						}
////						long end=System.currentTimeMillis();
//////						System.out.println("set "+cc+" 次 耗时："+(end-start)+"ms");
////						
////						 start=System.currentTimeMillis();
//						 
//						for (int i = 123; i < 256; i++) {
//////							byte[] b=(byte[])c.get(String.valueOf(i));
//							try {
//								int bookid=101591;
//								int cid=i;
//								String key="name_"+bookid+"_"+cid;
////								byte[] ss=(byte[])CacheUtil.getInstance(null).getBy(bookid, "con_"+bookid+"_"+cid).get(key);
////								System.out.println(cid+":"+new String(ss,"utf-8"));
//								String b=(String)CacheUtil.getInstance(null).getBy(bookid, key).get(key);
////								System.out.println(new String(b,"utf-8"));
//								System.out.println(i+" "+b);
////								CacheUtil.getInstance(null).getBy(bookid, key).delete(key);
////				 				key="para_"+bookid+"_"+cid;
////								CacheUtil.getInstance(null).getBy(bookid, key).delete(key);
//							} catch (Exception e) {
//								// TODO Auto-generated catch block
//								e.printStackTrace();
//							}
//////							System.out.println(Thread.currentThread().getId()+"========"+ss);
//						}
//						long end=System.currentTimeMillis();
//						System.out.println(Thread.currentThread().getId()+" get "+cc+" 次 耗时："+(end-start)+"ms");
//					}
//				});
//			}
		//			for (int i = 1; i < 504; i++) {
//				Object o= CacheUtil.getInstance(null).getBy(139350, "name_139350_"+i).get("name_139350_"+i);
////				if(o==null)
//				System.out.println(i+"========="+o);
//			}
//			String prekey="dir_";//2010 04-07 10:44设置进去
//			for (int i = 20000; i < 170000; i++) {
//				String key=prekey+i;
//				CacheUtil.getInstance(null).getBy(i, key).set(key,"", 0);
//				System.out.println("set key="+key);
//			}
//			for (int i = 1; i <= 170000; i++) {
//				String key=prekey+i+"_"+1+"_"+20;
//				CacheUtil.getInstance(null).getBy(152060, "info_152060").set("info_152060","");
//				System.out.println("set key="+key);
//		}
//			BaseBookDataImp b=new BaseBookDataImp();
//			b.getDirs(172052, 2, 10);
//////			TimeUnit.SECONDS.sleep(2);
//			int id=127470;
//			String key="menus_127470";
////			CacheUtil.getInstance(null).getBy(id, key).set(key,"");
//			for (int i = 0; i < 100000; i++) {
//				int t=((String)CacheUtil.getInstance(null).getBy(id, key).get(key)).length();
//				if(t==0)
//				System.out.println("--------i="+i);
//			}
			
			
//			System.out.println(CollectionUtils.toString(CacheUtil.getInstance(null).getStatus()));
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//如果读取缓存配置失败，则只使用主cache服务器
			log.error("", e);
			log.error("读取缓存配置失败，使用主cache服务器 ip="+Config.BOOK_CACHE_IP);
			try {
				CacheUtil.getInstance(Config.HOT_CACHE_NAME,new String[]{Config.BOOK_CACHE_IP+","+1});
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				log.error("",e);
			}
			
		}
		
		CachedClientFactory.clearAll();
	}
}
